//你这个学期必须选修 numCourse 门课程，记为 0 到 numCourse-1 。 
//
// 在选修某些课程之前需要一些先修课程。 例如，想要学习课程 0 ，你需要先完成课程 1 ，我们用一个匹配来表示他们：[0,1] 
//
// 给定课程总量以及它们的先决条件，请你判断是否可能完成所有课程的学习？ 
//
// 
//
// 示例 1: 
//
// 输入: 2, [[1,0]] 
//输出: true
//解释: 总共有 2 门课程。学习课程 1 之前，你需要完成课程 0。所以这是可能的。 
//
// 示例 2: 
//
// 输入: 2, [[1,0],[0,1]]
//输出: false
//解释: 总共有 2 门课程。学习课程 1 之前，你需要先完成​课程 0；并且学习课程 0 之前，你还应先完成课程 1。这是不可能的。 
//
// 
//
// 提示： 
//
// 
// 输入的先决条件是由 边缘列表 表示的图形，而不是 邻接矩阵 。详情请参见图的表示法。 
// 你可以假定输入的先决条件中没有重复的边。 
// 1 <= numCourses <= 10^5 
// 
// Related Topics 深度优先搜索 广度优先搜索 图 拓扑排序 
// 👍 665 👎 0

package com.leetcode.editor.cn;

import java.util.ArrayList;
import java.util.List;

//Java：课程表
class P207CourseSchedule {
    public static void main(String[] args) {
        Solution solution = new P207CourseSchedule().new Solution();
        // TO TEST
        int[][] p = {{1, 0}};
        System.out.println(solution.canFinish(2, p));
    }

    //leetcode submit region begin(Prohibit modification and deletion)
    class Solution {
        public boolean canFinish(int numCourses, int[][] prerequisites) {
            if (numCourses == 0) {
                return true;
            }
            List<List<Integer>> adj = new ArrayList<>(numCourses);
            for (int i = 0; i < numCourses; i++) {
                adj.add(new ArrayList<>());
            }
            for (int[] prerequisite : prerequisites) {
                adj.get(prerequisite[0]).add(prerequisite[1]);
            }
            //0-未访问;-1,被其它节点DFS访问;1，被当前节点dfs访问
            int[] flag = new int[numCourses];
            for (int i = 0; i < numCourses; i++) {
                boolean dfs = dfs(adj, flag, i);
                if (!dfs) {
                    return false;
                }
            }
            return true;
        }

        private boolean dfs(List<List<Integer>> adj, int[] flag, int i) {
            if (flag[i] == -1) {
                return true;
            }
            if (flag[i] == 1) {
                return false;
            }
            flag[i] = 1;
            for (Integer j : adj.get(i)) {
                boolean dfs = dfs(adj, flag, j);
                if (!dfs) {
                    return false;
                }
            }
            flag[i] = -1;
            return true;
        }
    }
//leetcode submit region end(Prohibit modification and deletion)

}